package com.oss.mq.service.impl;

import com.oss.mq.entity.pojo.ServiceRegister;
import com.oss.mq.mapper.ServiceRegisterMapper;
import com.oss.mq.mapper.TaskQueueMapper;
import com.oss.mq.entity.pojo.TaskQueue;
import com.oss.mq.service.ITaskQueueService;
import com.oss.mq.utils.MessageUtils;
import com.oss.mq.utils.SnowflakeUtils;
import lombok.experimental.Accessors;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Author yaoyaoyao
 * Date 2024/7/17 15:23
 */

@Service
public class TaskQueueServiceImpl implements ITaskQueueService {
    @Resource
    TaskQueueMapper taskQueueMapper;
    @Resource
    ServiceRegisterMapper registerMapper;
    @Autowired
    MessageUtils messageUtils;
    @Override
    public Integer addTaskQueue(TaskQueue taskQueue) {
        //生成任务存于任务队列中
        taskQueue.setIsValid("Y").setCreateDate(new Date()).setCreateUser(1)
                .setModifyDate(new Date()).setModifyUser(1)
                .setTaskQueueId(SnowflakeUtils.generate())
                .setTaskId(SnowflakeUtils.generate())
                .setTaskState("0").setAppId("A")
                .setProjectId(SnowflakeUtils.generate()).setSprintId(SnowflakeUtils.generate());

        //每当有新任务添加时就进行调度中心的执行流程
        taskQueueMapper.insertSelective(taskQueue);
        checkAndDistribute();

        return 1;
    }

    @Override
    public void deleteTaskQueue(Long id) {
        taskQueueMapper.deleteByPrimaryKey(id);
    }

    @Override
    public void modifyTaskQueue(TaskQueue taskQueue) {
        taskQueue.setModifyUser(1).setModifyDate(new Date());
        taskQueueMapper.updateByPrimaryKeySelective(taskQueue);
    }

    @Override
    public List<TaskQueue> selectTaskQueue() {
        return null;
    }

    //调度中心执行流程
    public synchronized void checkAndDistribute(){
        List<ServiceRegister> registers = registerMapper.selectAllLive();
        if(registers.size()!=0){
            List<ServiceRegister> liveRegisters = new ArrayList<>();
            for (ServiceRegister register:registers){
                //监听服务是否存活
                //如果上次心跳时间距离现在间隔大于十秒则判定为服务下线
                Date now = new Date();
                if((now.getTime()-register.getLateMonitorTime().getTime())>10000){
                    register.setServiceState("2").setModifyDate(new Date()).setModifyUser(1);
                    registerMapper.updateByPrimaryKeySelective(register);
                }else {
                    if(register.getServiceState().equals("0")){
                        liveRegisters.add(register);
                    }
                }
            }
            //选取一个当前存活且空闲的主机发送执行任务的消息
            ServiceRegister register = null;
            if(liveRegisters.size()!=0){
                register = liveRegisters.get(0);
            }
            System.out.println("reg"+register);
            //按权重顺序选择一个待执行任务
            TaskQueue task = taskQueueMapper.selectNextTask();
            System.out.println("task"+task);
            if(task!=null){
                Long taskId = task.getTaskId();
                if(register!=null){
                    //调度中心更新执行主机的注册表为运行状态
                    registerMapper.updateByPrimaryKeySelective(register.setServiceState("1"));
                    //更新任务为所属的执行主机和已分配待执行状态
                    task.setServiceId(register.getServiceId()).setTaskState("1")
                            .setModifyDate(new Date()).setModifyUser(1);
                    taskQueueMapper.updateByPrimaryKeySelective(task);

                    //发送任务
                    ServiceRegister finalRegister = register;
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            messageUtils.dispatchCenterSendMessage(finalRegister.getIp(),(byte) 1,"execute task_"+taskId);
                        }
                    }).start();

                }
            }
        }
    }
}
